package com.cinc.ebc.mm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cinc.ebc.mm.entity.*;
import com.cinc.ebc.mm.enums.MaterialPickingBillTypeEnum;
import com.cinc.ebc.mm.enums.MaterialPickingRetBillTypeEnum;
import com.cinc.ebc.mm.enums.MoveTypeEnum;
import com.cinc.ebc.mm.mapper.MmPurchaseOrderDetailMapper;
import com.cinc.ebc.mm.model.MmRptStockInOutStatModel;
import com.cinc.ebc.mm.service.IMmMaterialStockService;
import com.cinc.ebc.mm.service.IMmStockInOutService;
import com.cinc.ebc.mm.mapper.MmStockInOutDetailMapper;
import com.cinc.ebc.mm.mapper.MmStockInOutMapper;
import com.cinc.ebc.mm.model.MmStockInOutDetailModel;
import com.cinc.ebc.mm.vo.MmRptStockInOutStatPage;
import com.cinc.ebc.mm.vo.MmStockInOutDetailPage;
import com.cinc.mdm.constant.MdmConstant;
import com.cinc.mdm.modules.codeRule.service.IMdmCodeRuleService;
import com.cinc.mdm.modules.material.entity.MdmMaterial;
import com.cinc.mdm.modules.material.mapper.MdmMaterialMapper;
import com.cinc.mdm.modules.movementType.entity.MdmMovementType;
import com.cinc.mdm.modules.movementType.mapper.MdmMovementTypeMapper;
import com.cinc.mdm.modules.movementType.service.IMdmMovementTypeService;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 库存单据
 * @Author: jeecg-boot
 * @Date:   2022-04-05
 * @Version: V1.0
 */
@Service
public class MmStockInOutServiceImpl extends ServiceImpl<MmStockInOutMapper, MmStockInOut> implements IMmStockInOutService {

	@Autowired
	private MmStockInOutMapper mmStockInOutMapper;
	@Autowired
	private MmStockInOutDetailMapper mmStockInOutDetailMapper;
	@Autowired
	private IMdmMovementTypeService mdmMovementTypeService;
	@Autowired
	private IMmMaterialStockService mmMaterialStockService;
	@Autowired
	private MdmMovementTypeMapper mdmMovementTypeMapper;
	@Autowired
	private MmPurchaseOrderDetailMapper mmPurchaseOrderDetailMapper;
	@Autowired
	private IMdmCodeRuleService mdmCodeRuleService;
	@Autowired
	private MdmMaterialMapper mdmMaterialMapper;

	@Override
	@Transactional
	public void saveMain(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList) throws Exception {
		saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Override
	@Transactional
	public void saveMain(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList, boolean isAllocate) throws Exception {
		if(oConvertUtils.isEmpty(mmStockInOut.getBillNo())){
			mmStockInOut.setBillNo(mdmCodeRuleService.generateStockInOutCode());
		}
		if(oConvertUtils.isEmpty(mmStockInOut.getBillDate())){
			mmStockInOut.setBillDate(new Date());
		}
		mmStockInOutMapper.insert(mmStockInOut);
		if(mmStockInOutDetailList!=null && mmStockInOutDetailList.size()>0) {
			for(MmStockInOutDetail entity : mmStockInOutDetailList) {
				MdmMaterial mdmMaterial = mdmMaterialMapper.selectById(entity.getMaterialId());
				if(mdmMaterial == null){
					throw new RuntimeException("物料信息不存在");
				}
				//外键设置
				entity.setPid(mmStockInOut.getId());
				if(oConvertUtils.isNotEmpty(mmStockInOut.getWarehouseId())){
					entity.setWarehouseId(mmStockInOut.getWarehouseId());
				}
				mmStockInOutDetailMapper.insert(entity);
			}
			// 更新库存
			mmMaterialStockService.updateByStockInOutDetail(mmStockInOut, mmStockInOutDetailList, isAllocate);
			// 更新业务单据
			updateSourceOrder(mmStockInOut, mmStockInOutDetailList);
		}
	}

	private void updateSourceOrder(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList){
		MdmMovementType mdmMovementType = mdmMovementTypeMapper.selectById(mmStockInOut.getMoveId());
		if(mdmMovementType == null){
			return;
		}
		for(MmStockInOutDetail stockInOutDetail : mmStockInOutDetailList){
			String sourceId = stockInOutDetail.getSourceId();
			if(StringUtils.isBlank(sourceId)){
				continue;
			}
			if(MdmConstant.MOVE_TYPE101.equals(mdmMovementType.getTypeNo()) || MdmConstant.MOVE_TYPE102.equals(mdmMovementType.getTypeNo())){
				// 采购单
				MmPurchaseOrderDetail modify = new MmPurchaseOrderDetail();
				modify.setId(sourceId);
				MmPurchaseOrderDetail purchaseOrderDetail= mmPurchaseOrderDetailMapper.selectById(sourceId);
				modify.setInQty(purchaseOrderDetail.getInQty().add(stockInOutDetail.getQty()));
				if(modify.getInQty().compareTo(purchaseOrderDetail.getPurQty()) >= 0){
					modify.setStatus(MdmConstant.PUR_FINISH);
				}else if(modify.getInQty().compareTo(BigDecimal.ZERO) == 1){
					modify.setStatus(MdmConstant.PUR_HANDLE);
				}else{
					modify.setStatus(MdmConstant.PUR_NEW);
				}
				mmPurchaseOrderDetailMapper.updateById(modify);
			}else{
				continue;
			}
		}
	}

	@Override
	@Transactional
	public void updateMain(MmStockInOut mmStockInOut,List<MmStockInOutDetail> mmStockInOutDetailList) {
		mmStockInOutMapper.updateById(mmStockInOut);

		//1.先删除子表数据
		mmStockInOutDetailMapper.deleteByMainId(mmStockInOut.getId());

		//2.子表数据重新插入
		if(mmStockInOutDetailList!=null && mmStockInOutDetailList.size()>0) {
			for(MmStockInOutDetail entity:mmStockInOutDetailList) {
				//外键设置
				entity.setPid(mmStockInOut.getId());
				mmStockInOutDetailMapper.insert(entity);
			}
		}
	}

	@Override
	@Transactional
	public void delMain(String id) {
		mmStockInOutDetailMapper.deleteByMainId(id);
		mmStockInOutMapper.deleteById(id);
	}

	@Override
	@Transactional
	public void delBatchMain(Collection<? extends Serializable> idList) {
		for(Serializable id:idList) {
			mmStockInOutDetailMapper.deleteByMainId(id.toString());
			mmStockInOutMapper.deleteById(id);
		}
	}

	@Override
	public Page<MmStockInOutDetailModel> purchaseInPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage){
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE101);
		if(StringUtils.isBlank(moveId)){
			return null;
		}
		mmStockInOutDetailPage.setMoveId(moveId);

		return page.setRecords(mmStockInOutDetailMapper.selectPurchaseInOutList(page, mmStockInOutDetailPage));
	}

	@Override
	public Page<MmStockInOutDetailModel> purchaseBackPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage){
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE122);
		if(StringUtils.isBlank(moveId)){
			return null;
		}
		mmStockInOutDetailPage.setMoveId(moveId);

		return page.setRecords(mmStockInOutDetailMapper.selectPurchaseInOutList(page, mmStockInOutDetailPage));
	}

	@Override
	@Transactional
	public void saveMainPurchaseIn(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList) throws Exception {
		if(StringUtils.isBlank(mmStockInOut.getSupplyId())){
			throw new RuntimeException("供应商不能为空");
		}
		if(StringUtils.isBlank(mmStockInOut.getWarehouseId())){
			throw new RuntimeException("库房不能为空");
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE101);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.IN);

		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Override
	@Transactional
	public void saveMainPurchaseBack(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList) throws Exception {
		if(StringUtils.isBlank(mmStockInOut.getSupplyId())){
			throw new RuntimeException("供应商不能为空");
		}
		if(StringUtils.isBlank(mmStockInOut.getWarehouseId())){
			throw new RuntimeException("库房不能为空");
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE122);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.OUT);

		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Override
	public Page<MmStockInOutDetailModel> otherInPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage) {
		mmStockInOutDetailPage.setIoFlag(MdmConstant.IN);
		mmStockInOutDetailPage.setOtherFlag(MdmConstant.YES);
		String sql = QueryGenerator.installAuthJdbc(MmPurchaseOrder.class);
		return page.setRecords(mmStockInOutDetailMapper.selectDetailList(page, mmStockInOutDetailPage, sql));
	}

	@Override
	public Page<MmStockInOutDetailModel> otherOutPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage) {
		mmStockInOutDetailPage.setIoFlag(MdmConstant.OUT);
		mmStockInOutDetailPage.setOtherFlag(MdmConstant.YES);
		String sql = QueryGenerator.installAuthJdbc(MmPurchaseOrder.class);
		return page.setRecords(mmStockInOutDetailMapper.selectDetailList(page, mmStockInOutDetailPage, sql));
	}

	@Override
	public Page<MmStockInOutDetailModel> inventoryProfitPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage) {
		mmStockInOutDetailPage.setIoFlag(MdmConstant.IN);
		mmStockInOutDetailPage.setMoveTypeNo(MdmConstant.MOVE_TYPE701);
		String sql = QueryGenerator.installAuthJdbc(MmPurchaseOrder.class);
		return page.setRecords(mmStockInOutDetailMapper.selectDetailList(page, mmStockInOutDetailPage, sql));
	}

	@Override
	public Page<MmStockInOutDetailModel> inventoryLossPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage) {
		mmStockInOutDetailPage.setIoFlag(MdmConstant.OUT);
		mmStockInOutDetailPage.setMoveTypeNo(MdmConstant.MOVE_TYPE702);
		String sql = QueryGenerator.installAuthJdbc(MmPurchaseOrder.class);
		return page.setRecords(mmStockInOutDetailMapper.selectDetailList(page, mmStockInOutDetailPage, sql));
	}

	@Override
	public void detaiPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage detailPage) {

		page.setRecords(mmStockInOutDetailMapper.selectDetailList(page, detailPage, null));
	}

	@Override
	public List<MmStockInOutDetailModel> detailList(MmStockInOutDetailPage detailPage) {
		return mmStockInOutDetailMapper.selectDetailList(null, detailPage, null);
	}

	/**
	 * 单据冲销
	 *
	 * @param detailPageList
	 * @return void
	 * @throws
	 */
	@Override
	@Transactional
	public void writeOff(List<MmStockInOutDetailPage> detailPageList) throws Exception {
		List<String> idList = detailPageList.stream().map(MmStockInOutDetailPage::getId).collect(Collectors.toList());
		QueryWrapper<MmStockInOutDetail> detailQuery = new QueryWrapper<>();
		detailQuery.in("id", idList).eq("handle_flag","1");
		int count = mmStockInOutDetailMapper.selectCount(detailQuery);
		if(count > 0){
			throw new RuntimeException("冲销单据不能再次冲销");
		}

		Map<String, List<MmStockInOutDetailPage>> addMap = detailPageList.stream().collect(Collectors.groupingBy(MmStockInOutDetailPage::getPid));
		for(String pid : addMap.keySet()){
			// 主记录
			MmStockInOut mmStockInOut = mmStockInOutMapper.selectById(pid);
			MmStockInOut mmStockInOutAdd = new MmStockInOut();
			BeanUtils.copyProperties(mmStockInOut, mmStockInOutAdd);
			mmStockInOutAdd.setId(null);
			mmStockInOutAdd.setUpdateBy(null);
			mmStockInOutAdd.setUpdateTime(null);
			mmStockInOutAdd.setRemark(null);
			mmStockInOutAdd.setVoucherNo(null);
			mmStockInOutAdd.setVoucherDate(null);
			mmStockInOutAdd.setCreateTime(null);
			// 反向移动类型
			MdmMovementType mdmMovementType = mdmMovementTypeMapper.selectById(mmStockInOut.getMoveId());
			if(oConvertUtils.isEmpty(mdmMovementType.getReverseId())){
				throw new RuntimeException(mdmMovementType.getTypeName() + " 反向移动类型设置有误");
			}
			mmStockInOutAdd.setMoveId(mdmMovementType.getReverseId());
			// 单据编号
			String billNo = mdmCodeRuleService.generateStockInOutCode();
			mmStockInOutAdd.setBillNo(billNo);
			// 冲销单据号
			mmStockInOutAdd.setCancelBillNo(mmStockInOut.getBillNo());

			// 明细
			List<MmStockInOutDetail> mmStockInOutDetailAddList = new ArrayList<>();
			List<MmStockInOutDetail> mmStockInOutDetailModifyList = new ArrayList<>();
			List<String> detailIdList = addMap.get(pid).stream().map(MmStockInOutDetailPage::getId).collect(Collectors.toList());
			QueryWrapper<MmStockInOutDetail> queryWrapper = new QueryWrapper<>();
			queryWrapper.in("id",detailIdList);
			List<MmStockInOutDetail> mmStockInOutDetailList = mmStockInOutDetailMapper.selectList(queryWrapper);
			for(MmStockInOutDetail detail : mmStockInOutDetailList){
				// 冲销明细
				MmStockInOutDetail mmStockInOutDetailAdd = new MmStockInOutDetail();
				BeanUtils.copyProperties(detail, mmStockInOutDetailAdd);
				mmStockInOutDetailAdd.setId(null);
				mmStockInOutDetailAdd.setQty(detail.getQty().multiply(BigDecimal.valueOf(-1)));
				mmStockInOutDetailAdd.setSumPrice(detail.getSumPrice().multiply(BigDecimal.valueOf(-1)));
				mmStockInOutDetailAdd.setHandleFlag("1");
				mmStockInOutDetailAdd.setCancelDetailId(detail.getId());
				mmStockInOutDetailAddList.add(mmStockInOutDetailAdd);
				// 添加到更新列表
				MmStockInOutDetail mmStockInOutDetailModify = new MmStockInOutDetail();
				mmStockInOutDetailModify.setId(detail.getId());
				mmStockInOutDetailModify.setHandleFlag("1");
				mmStockInOutDetailModifyList.add(mmStockInOutDetailModify);
			}

			// 保存数据
			this.saveMain(mmStockInOutAdd, mmStockInOutDetailAddList, false);

			// 更新源单据
			for(MmStockInOutDetail inOutDetailModify : mmStockInOutDetailModifyList){
				mmStockInOutDetailMapper.updateById(inOutDetailModify);
			}
		}
	}

	@Override
	public void saveMainInventoryProfit(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList)  throws Exception {
		if(StringUtils.isBlank(mmStockInOut.getWarehouseId())){
			throw new RuntimeException("库房不能为空");
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE701);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.IN);

		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Override
	public void saveMainInventoryLoss(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList)  throws Exception {
		if(StringUtils.isBlank(mmStockInOut.getWarehouseId())){
			throw new RuntimeException("库房不能为空");
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE702);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.OUT);

		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Transactional
	@Override
	public void saveMainSalesOut(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList, boolean isAllocate)  throws Exception {
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE601);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.OUT);

		this.saveMain(mmStockInOut, mmStockInOutDetailList,isAllocate);
	}

	@Override
	public void saveMainSalesReturn(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList)  throws Exception {
		String moveId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE602);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.OUT);

		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Transactional
	@Override
	public void saveMainMaterialPicking(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList, MmMaterialPicking materialPicking) throws Exception {
		String moveTypeNo = null;
		if(materialPicking.getBillType().equals(MaterialPickingBillTypeEnum.TYPE01.getCode())){
			moveTypeNo = MoveTypeEnum.TYPE261.getCode();
		}else{
			moveTypeNo = MoveTypeEnum.TYPE201.getCode();
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(moveTypeNo);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		mmStockInOut.setMoveId(moveId);
		mmStockInOut.setIoFlag(MdmConstant.OUT);
		this.saveMain(mmStockInOut, mmStockInOutDetailList, false);
	}

	@Override
	public IPage<MmRptStockInOutStatModel> queryRptStockInOutStatList(Page<MmRptStockInOutStatModel> page, MmRptStockInOutStatPage mmRptStockInOutStatPage) {
		return page.setRecords(mmStockInOutMapper.selectRptStockInOutStatList(page, mmRptStockInOutStatPage));
	}

	@Override
	public Page<MmStockInOutDetailModel> rptPage(Page<MmStockInOutDetailModel> page, MmStockInOutDetailPage mmStockInOutDetailPage) {
		return page.setRecords(mmStockInOutMapper.selectRptList(page, mmStockInOutDetailPage));
	}

	@Override
	public void saveMainMaterialPickingRet(MmStockInOut stockInOut, List<MmStockInOutDetail> stockInOutDetailList, MmMaterialPickingRet materialPickingRet) throws Exception {
		String moveTypeNo = null;
		if(materialPickingRet.getBillType().equals(MaterialPickingRetBillTypeEnum.TYPE01.getCode())){
			moveTypeNo = MoveTypeEnum.TYPE262.getCode();
		}else{
			moveTypeNo = MoveTypeEnum.TYPE202.getCode();
		}
		String moveId = mdmMovementTypeService.findIdByTypeNo(moveTypeNo);
		if(StringUtils.isBlank(moveId)){
			throw new RuntimeException("移动类型设置错误");
		}
		stockInOut.setMoveId(moveId);
		stockInOut.setIoFlag(MdmConstant.OUT);
		this.saveMain(stockInOut, stockInOutDetailList, false);
	}
}
